﻿using System;
using System.Linq;
using System.Windows.Ink;
using System.Windows.Markup;
using System.Xml.Linq;

using FirstFloor.Documents.Annotations.Storage;

namespace SampleBrowser.Common.Annotations
{
    /// <summary>
    /// Reads and writes Ink annotations.
    /// </summary>
    /// <remarks>
    /// The Ink factory provides persistence to an XML based store.
    /// </remarks>
    public class InkFactory
        : AnnotationFactory<Ink>
    {
        private const string NamespaceXaml = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        /// <summary>
        /// Initializes a new instance of the <see cref="InkFactory"/> class.
        /// </summary>
        public InkFactory()
            : base(Ink.TypeInk)
        {
        }

        /// <summary>
        /// Creates the annotation.
        /// </summary>
        /// <returns>The annotation.</returns>
        public override Ink CreateAnnotation()
        {
            return new Ink();
        }

        /// <summary>
        /// Read an annotation from given element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The annotation.</returns>
        protected override Ink Read(XElement element)
        {
            var ink = base.Read(element);
            ink.PageNumber = (int)element.Attribute("PageNumber");

            var strokesElement = element.Element(XName.Get("StrokeCollection", NamespaceXaml));
            var strokes = (StrokeCollection)XamlReader.Load(strokesElement.ToString(SaveOptions.None));
            foreach (var stroke in strokes) {
                ink.Strokes.Add(stroke);
            }

            return ink;
        }

        /// <summary>
        /// Write an annotation.
        /// </summary>
        /// <param name="annotation">The annotation.</param>
        /// <returns>
        /// The XML element representing the annotation.
        /// </returns>
        protected override XElement Write(Ink annotation)
        {
            // write strokes in proper XAML notation, so we can use XamlReader to read

            // note: this is pretty verbose XML, you may want to consider compression to
            // decrease the size of generated XML

            var element = base.Write(annotation);
            element.Add(
                new XAttribute("PageNumber", annotation.PageNumber),
                new XElement(XName.Get("StrokeCollection", NamespaceXaml),
                    from stroke in annotation.Strokes
                    select new XElement(XName.Get("Stroke", NamespaceXaml),
                        new XElement(XName.Get("Stroke.DrawingAttributes", NamespaceXaml),
                            new XElement(XName.Get("DrawingAttributes", NamespaceXaml),
                                new XAttribute("Width", stroke.DrawingAttributes.Width),
                                new XAttribute("Height", stroke.DrawingAttributes.Height),
                                new XAttribute("Color", stroke.DrawingAttributes.Color))),
                        new XElement(XName.Get("Stroke.StylusPoints", NamespaceXaml),
                            new XElement(XName.Get("StylusPointCollection", NamespaceXaml),
                                from point in stroke.StylusPoints
                                select new XElement(XName.Get("StylusPoint", NamespaceXaml),
                                    new XAttribute("X", point.X),
                                    new XAttribute("Y", point.Y)))))));

            return element;
        }
    }
}
